#include "lcd.h"

extern SPI_HandleTypeDef Spi1Handle;
extern DMA_HandleTypeDef HdmaCh1;

void LCD_GPIO_Init(void)
{
  __HAL_RCC_GPIOA_CLK_ENABLE();
  GPIO_InitTypeDef  GPIO_InitStruct;

  GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;            /* 推挽输出 */
  GPIO_InitStruct.Pull = GPIO_NOPULL;                    /* 使能上拉 */
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;          /* GPIO速度 */
  /* GPIO初始化 */
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

void LCD_Writ_Bus(uint8_t dat)
{
//  LCD_CS_Clr();
//  while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);//¼ì²é½ÓÊÕ±êÖ¾Î»
//  SPI_I2S_SendData(SPI1, dat);
////  delay(1);
//  LCD_CS_Set();

  LCD_CS_Clr();
  HAL_SPI_Transmit_DMA(&Spi1Handle, (uint8_t*)&dat, 1);
  while(Spi1Handle.State != HAL_SPI_STATE_READY)
  {
  }
  LCD_CS_Set();
}

void LCD_WR_DATA8(uint8_t dat)
{
  LCD_Writ_Bus(dat);
}

void LCD_WR_DATA(uint16_t dat)
{
  LCD_Writ_Bus(dat >> 8);
  LCD_Writ_Bus(dat);
}

void LCD_WR_REG(uint8_t dat)
{
  LCD_DC_Clr();//Ð´ÃüÁî
  LCD_Writ_Bus(dat);
  LCD_DC_Set();//Ð´Êý¾Ý
}

/******************************************************************************
      º¯ÊýËµÃ÷£ºÉèÖÃÆðÊ¼ºÍ½áÊøµØÖ·
      Èë¿ÚÊý¾Ý£ºx1,x2 ÉèÖÃÁÐµÄÆðÊ¼ºÍ½áÊøµØÖ·
                y1,y2 ÉèÖÃÐÐµÄÆðÊ¼ºÍ½áÊøµØÖ·
      ·µ»ØÖµ£º  ÎÞ
******************************************************************************/
void LCD_Address_Set(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
  if(USE_HORIZONTAL == 0)
  {
    LCD_WR_REG(0x2a);//ÁÐµØÖ·ÉèÖÃ
    LCD_WR_DATA(x1 + 34);
    LCD_WR_DATA(x2 + 34);
    LCD_WR_REG(0x2b);//ÐÐµØÖ·ÉèÖÃ
    LCD_WR_DATA(y1);
    LCD_WR_DATA(y2);
    LCD_WR_REG(0x2c);//´¢´æÆ÷Ð´
  }
  else if(USE_HORIZONTAL == 1)
  {
    LCD_WR_REG(0x2a);//ÁÐµØÖ·ÉèÖÃ
    LCD_WR_DATA(x1 + 34);
    LCD_WR_DATA(x2 + 34);
    LCD_WR_REG(0x2b);//ÐÐµØÖ·ÉèÖÃ
    LCD_WR_DATA(y1);
    LCD_WR_DATA(y2);
    LCD_WR_REG(0x2c);//´¢´æÆ÷Ð´
  }
  else if(USE_HORIZONTAL == 2)
  {
    LCD_WR_REG(0x2a);//ÁÐµØÖ·ÉèÖÃ
    LCD_WR_DATA(x1);
    LCD_WR_DATA(x2);
    LCD_WR_REG(0x2b);//ÐÐµØÖ·ÉèÖÃ
    LCD_WR_DATA(y1 + 34);
    LCD_WR_DATA(y2 + 34);
    LCD_WR_REG(0x2c);//´¢´æÆ÷Ð´
  }
  else
  {
    LCD_WR_REG(0x2a);//ÁÐµØÖ·ÉèÖÃ
    LCD_WR_DATA(x1);
    LCD_WR_DATA(x2);
    LCD_WR_REG(0x2b);//ÐÐµØÖ·ÉèÖÃ
    LCD_WR_DATA(y1 + 34);
    LCD_WR_DATA(y2 + 34);
    LCD_WR_REG(0x2c);//´¢´æÆ÷Ð´
  }
}

void LCD_Init(void)
{
  LCD_GPIO_Init();//³õÊ¼»¯GPIO
  dma_mode1_config();

  LCD_RES_Clr();//¸´Î»
  HAL_Delay(30);
  LCD_RES_Set();
  HAL_Delay(100);
//
  LCD_WR_REG(0x11);
//	delay_ms(120);
  LCD_WR_REG(0x36);
  if(USE_HORIZONTAL == 0)LCD_WR_DATA8(0x00);
  else if(USE_HORIZONTAL == 1)LCD_WR_DATA8(0xC0);
  else if(USE_HORIZONTAL == 2)LCD_WR_DATA8(0x70);
  else LCD_WR_DATA8(0xA0);

  LCD_WR_REG(0x3A);
  LCD_WR_DATA8(0x05);

  LCD_WR_REG(0xB2);
  LCD_WR_DATA8(0x0C);
  LCD_WR_DATA8(0x0C);
  LCD_WR_DATA8(0x00);
  LCD_WR_DATA8(0x33);
  LCD_WR_DATA8(0x33);

  LCD_WR_REG(0xB7);
  LCD_WR_DATA8(0x35);

  LCD_WR_REG(0xBB);
  LCD_WR_DATA8(0x35);

  LCD_WR_REG(0xC0);
  LCD_WR_DATA8(0x2C);

  LCD_WR_REG(0xC2);
  LCD_WR_DATA8(0x01);

  LCD_WR_REG(0xC3);
  LCD_WR_DATA8(0x13);

  LCD_WR_REG(0xC4);
  LCD_WR_DATA8(0x20);

  LCD_WR_REG(0xC6);
  LCD_WR_DATA8(0x0F);

  LCD_WR_REG(0xD0);
  LCD_WR_DATA8(0xA4);
  LCD_WR_DATA8(0xA1);

  LCD_WR_REG(0xD6);
  LCD_WR_DATA8(0xA1);

  LCD_WR_REG(0xE0);
  LCD_WR_DATA8(0xF0);
  LCD_WR_DATA8(0x00);
  LCD_WR_DATA8(0x04);
  LCD_WR_DATA8(0x04);
  LCD_WR_DATA8(0x04);
  LCD_WR_DATA8(0x05);
  LCD_WR_DATA8(0x29);
  LCD_WR_DATA8(0x33);
  LCD_WR_DATA8(0x3E);
  LCD_WR_DATA8(0x38);
  LCD_WR_DATA8(0x12);
  LCD_WR_DATA8(0x12);
  LCD_WR_DATA8(0x28);
  LCD_WR_DATA8(0x30);

  LCD_WR_REG(0xE1);
  LCD_WR_DATA8(0xF0);
  LCD_WR_DATA8(0x07);
  LCD_WR_DATA8(0x0A);
  LCD_WR_DATA8(0x0D);
  LCD_WR_DATA8(0x0B);
  LCD_WR_DATA8(0x07);
  LCD_WR_DATA8(0x28);
  LCD_WR_DATA8(0x33);
  LCD_WR_DATA8(0x3E);
  LCD_WR_DATA8(0x36);
  LCD_WR_DATA8(0x14);
  LCD_WR_DATA8(0x14);
  LCD_WR_DATA8(0x29);
  LCD_WR_DATA8(0x32);

// 	LCD_WR_REG(0x2A);
//	LCD_WR_DATA8(0x00);
//	LCD_WR_DATA8(0x22);
//	LCD_WR_DATA8(0x00);
//	LCD_WR_DATA8(0xCD);
//	LCD_WR_DATA8(0x2B);
//	LCD_WR_DATA8(0x00);
//	LCD_WR_DATA8(0x00);
//	LCD_WR_DATA8(0x01);
//	LCD_WR_DATA8(0x3F);
//	LCD_WR_REG(0x2C);
  LCD_WR_REG(0x21);

  LCD_WR_REG(0x11);
  HAL_Delay(120);
  LCD_WR_REG(0x29);

  LCD_Fill(0, 0, LCD_W, LCD_H, WHITE);
  LCD_BLK_Set();
}

void LCD_Fill(uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend, uint16_t color)
{
  uint16_t num = (xend - xsta) * (yend - ysta);
  LCD_Address_Set(xsta, ysta, xend - 1, yend - 1); //ÉèÖÃÏÔÊ¾·¶Î§
  // DMA填色
  dma_mode2_config();
  Spi1Handle.Init.DataSize = SPI_DATASIZE_16BIT;
  HAL_SPI_DeInit(&Spi1Handle);
  /*SPI初始化*/
  HAL_SPI_Init(&Spi1Handle);
  // ************
  
  LCD_CS_Clr();
  HAL_SPI_Transmit_DMA(&Spi1Handle, (uint8_t*)&color, num);
  while(Spi1Handle.State != HAL_SPI_STATE_READY)
  {
  }
  LCD_CS_Set();
  dma_mode1_config();
  
  // 重新修改为8位
  Spi1Handle.Init.DataSize = SPI_DATASIZE_8BIT;
  HAL_SPI_DeInit(&Spi1Handle);
  /*SPI初始化*/
  HAL_SPI_Init(&Spi1Handle);
}

void LCD_DrawPoint(uint16_t x, uint16_t y, uint16_t color)
{
  LCD_Address_Set(x, y, x, y); //ÉèÖÃ¹â±êÎ»ÖÃ
  LCD_WR_DATA(color);
}

/******************************************************************************
      º¯ÊýËµÃ÷£º»­Ïß
      Èë¿ÚÊý¾Ý£ºx1,y1   ÆðÊ¼×ø±ê
                x2,y2   ÖÕÖ¹×ø±ê
                color   ÏßµÄÑÕÉ«
      ·µ»ØÖµ£º  ÎÞ
******************************************************************************/
void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
  uint16_t t;
  int xerr = 0, yerr = 0, delta_x, delta_y, distance;
  int incx, incy, uRow, uCol;
  delta_x = x2 - x1; //¼ÆËã×ø±êÔöÁ¿
  delta_y = y2 - y1;
  uRow = x1; //»­ÏßÆðµã×ø±ê
  uCol = y1;
  if(delta_x > 0)incx = 1; //ÉèÖÃµ¥²½·½Ïò
  else if(delta_x == 0)incx = 0; //´¹Ö±Ïß
  else
  {
    incx = -1;
    delta_x = -delta_x;
  }
  if(delta_y > 0)incy = 1;
  else if(delta_y == 0)incy = 0; //Ë®Æ½Ïß
  else
  {
    incy = -1;
    delta_y = -delta_y;
  }
  if(delta_x > delta_y)distance = delta_x; //Ñ¡È¡»ù±¾ÔöÁ¿×ø±êÖá
  else distance = delta_y;
  for(t = 0; t < distance + 1; t++)
  {
    LCD_DrawPoint(uRow, uCol, color); //»­µã
    xerr += delta_x;
    yerr += delta_y;
    if(xerr > distance)
    {
      xerr -= distance;
      uRow += incx;
    }
    if(yerr > distance)
    {
      yerr -= distance;
      uCol += incy;
    }
  }
}


/******************************************************************************
      º¯ÊýËµÃ÷£º»­¾ØÐÎ
      Èë¿ÚÊý¾Ý£ºx1,y1   ÆðÊ¼×ø±ê
                x2,y2   ÖÕÖ¹×ø±ê
                color   ¾ØÐÎµÄÑÕÉ«
      ·µ»ØÖµ£º  ÎÞ
******************************************************************************/
void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
  LCD_DrawLine(x1, y1, x2, y1, color);
  LCD_DrawLine(x1, y1, x1, y2, color);
  LCD_DrawLine(x1, y2, x2, y2, color);
  LCD_DrawLine(x2, y1, x2, y2, color);
}


/******************************************************************************
      º¯ÊýËµÃ÷£º»­Ô²
      Èë¿ÚÊý¾Ý£ºx0,y0   Ô²ÐÄ×ø±ê
                r       °ë¾¶
                color   Ô²µÄÑÕÉ«
      ·µ»ØÖµ£º  ÎÞ
******************************************************************************/
void Draw_Circle(uint16_t x0, uint16_t y0, uint8_t r, uint16_t color)
{
  int a, b;
  a = 0;
  b = r;
  while(a <= b)
  {
    LCD_DrawPoint(x0 - b, y0 - a, color);       //3
    LCD_DrawPoint(x0 + b, y0 - a, color);       //0
    LCD_DrawPoint(x0 - a, y0 + b, color);       //1
    LCD_DrawPoint(x0 - a, y0 - b, color);       //2
    LCD_DrawPoint(x0 + b, y0 + a, color);       //4
    LCD_DrawPoint(x0 + a, y0 - b, color);       //5
    LCD_DrawPoint(x0 + a, y0 + b, color);       //6
    LCD_DrawPoint(x0 - b, y0 + a, color);       //7
    a++;
    if((a * a + b * b) > (r * r)) //ÅÐ¶ÏÒª»­µÄµãÊÇ·ñ¹ýÔ¶
    {
      b--;
    }
  }
}

void LCD_ShowPicture(uint16_t x, uint16_t y, uint16_t length, uint16_t width, const uint8_t pic[])
{
  uint16_t num;
  num = length * width * 2;
  LCD_Address_Set(x, y, x + length - 1, y + width - 1);
  LCD_CS_Clr();
//	MYDMA_Config(DMA1_Channel3,(u32)&SPI1->DR,(u32)pic,num);
//	SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Tx,ENABLE);
//	MYDMA_Enable(DMA1_Channel3);
//	while(1)
//	{
//		if(DMA_GetFlagStatus(DMA1_FLAG_TC3)!=RESET)//µÈ´ýÍ¨µÀ4´«ÊäÍê³É
//		{
//			DMA_ClearFlag(DMA1_FLAG_TC3);//Çå³ýÍ¨µÀ3´«ÊäÍê³É±êÖ¾
//			break;
//		}
//	}
  HAL_SPI_Transmit_DMA(&Spi1Handle, (uint8_t*)pic, num);
  while(Spi1Handle.State != HAL_SPI_STATE_READY)
  {
  }
  LCD_CS_Set();
}

void LCD_ShowChar(uint16_t x, uint16_t y, uint8_t num, uint16_t fc, uint16_t bc, uint8_t sizey, uint8_t mode)
{
  uint8_t temp, sizex, t, m = 0;
  uint16_t i, TypefaceNum; //Ò»¸ö×Ö·ûËùÕ¼×Ö½Ú´óÐ¡
  uint16_t x0 = x;
  sizex = sizey / 2;
  TypefaceNum = (sizex / 8 + ((sizex % 8) ? 1 : 0)) * sizey;
  num = num - ' '; //µÃµ½Æ«ÒÆºóµÄÖµ
  LCD_Address_Set(x, y, x + sizex - 1, y + sizey - 1); //ÉèÖÃ¹â±êÎ»ÖÃ
  for(i = 0; i < TypefaceNum; i++)
  {
    if(sizey == 12)temp = ascii_1206[num][i];		   //µ÷ÓÃ6x12×ÖÌå
    else if(sizey == 16)temp = ascii_1608[num][i];		 //µ÷ÓÃ8x16×ÖÌå
    else if(sizey == 24)temp = ascii_2412[num][i];		 //µ÷ÓÃ12x24×ÖÌå
    else if(sizey == 32)temp = ascii_3216[num][i];		 //µ÷ÓÃ16x32×ÖÌå
    else return;
    for(t = 0; t < 8; t++)
    {
      if(!mode)//·Çµþ¼ÓÄ£Ê½
      {
        if(temp & (0x01 << t))LCD_WR_DATA(fc);
        else LCD_WR_DATA(bc);
        m++;
        if(m % sizex == 0)
        {
          m = 0;
          break;
        }
      }
      else//µþ¼ÓÄ£Ê½
      {
        if(temp & (0x01 << t))LCD_DrawPoint(x, y, fc); //»­Ò»¸öµã
        x++;
        if((x - x0) == sizex)
        {
          x = x0;
          y++;
          break;
        }
      }
    }
  }
}

void LCD_ShowString(uint16_t x, uint16_t y, const uint8_t* p, uint16_t fc, uint16_t bc, uint8_t sizey, uint8_t mode)
{
  while(*p != '\0')
  {
    LCD_ShowChar(x, y, *p, fc, bc, sizey, mode);
    x += sizey / 2;
    p++;
  }
}

uint32_t mypow(uint8_t m, uint8_t n)
{
  uint32_t result = 1;
  while(n--)result *= m;
  return result;
}

void LCD_ShowIntNum(uint16_t x, uint16_t y, uint16_t num, uint8_t len, uint16_t fc, uint16_t bc, uint8_t sizey)
{
  uint8_t t, temp;
  uint8_t enshow = 0;
  uint8_t sizex = sizey / 2;
  for(t = 0; t < len; t++)
  {
    temp = (num / mypow(10, len - t - 1)) % 10;
    if(enshow == 0 && t < (len - 1))
    {
      if(temp == 0)
      {
        LCD_ShowChar(x + t * sizex, y, ' ', fc, bc, sizey, 0);
        continue;
      }
      else enshow = 1;

    }
    LCD_ShowChar(x + t * sizex, y, temp + 48, fc, bc, sizey, 0);
  }
}

void LCD_ShowCross(uint16_t x, uint16_t y, uint16_t fc)
{
  LCD_DrawLine(x - 10, y, x + 10, y, fc);
  LCD_DrawLine(x, y - 10, x, y + 10, fc);
}

void LCD_ShowFloatNum1(uint16_t x, uint16_t y, float num, uint8_t len, uint16_t fc, uint16_t bc, uint8_t sizey)
{
  uint8_t t, temp, sizex;
  uint16_t num1;
  sizex = sizey / 2;
  num1 = num * 100;
  for(t = 0; t < len; t++)
  {
    temp = (num1 / mypow(10, len - t - 1)) % 10;
    if(t == (len - 2))
    {
      LCD_ShowChar(x + (len - 2)*sizex, y, '.', fc, bc, sizey, 0);
      t++;
      len += 1;
    }
    LCD_ShowChar(x + t * sizex, y, temp + 48, fc, bc, sizey, 0);
  }
}

void dma_mode1_config(void)
{
  /*DMA_CH1配置*/
  HdmaCh1.Instance                 = DMA1_Channel1;
  HdmaCh1.Init.Direction           = DMA_MEMORY_TO_PERIPH;
  HdmaCh1.Init.PeriphInc           = DMA_PINC_DISABLE;
  HdmaCh1.Init.MemInc              = DMA_MINC_ENABLE;
  HdmaCh1.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
  HdmaCh1.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
  HdmaCh1.Init.Mode                = DMA_NORMAL;
  HdmaCh1.Init.Priority            = DMA_PRIORITY_VERY_HIGH;
  HAL_DMA_DeInit(&HdmaCh1);
  /*DMA初始化*/
  HAL_DMA_Init(&HdmaCh1);
  /*DMA句柄关联到SPI句柄*/
  __HAL_LINKDMA(&Spi1Handle, hdmatx, HdmaCh1);

  /*DMA中断设置*/
  HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);

//  Spi1Handle.Init.DataSize = SPI_DATASIZE_8BIT;
//  HAL_SPI_DeInit(&Spi1Handle);
//  /*SPI初始化*/
//  HAL_SPI_Init(&Spi1Handle);
}

void dma_mode2_config(void)
{
  /*DMA_CH1配置*/
  HdmaCh1.Instance                 = DMA1_Channel1;
  HdmaCh1.Init.Direction           = DMA_MEMORY_TO_PERIPH;
  HdmaCh1.Init.PeriphInc           = DMA_PINC_DISABLE;
  HdmaCh1.Init.MemInc              = DMA_MINC_DISABLE;
  HdmaCh1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
  HdmaCh1.Init.MemDataAlignment    = DMA_MDATAALIGN_HALFWORD;
  HdmaCh1.Init.Mode                = DMA_NORMAL;
  HdmaCh1.Init.Priority            = DMA_PRIORITY_VERY_HIGH;
  HAL_DMA_DeInit(&HdmaCh1);
  /*DMA初始化*/
  HAL_DMA_Init(&HdmaCh1);
  /*DMA句柄关联到SPI句柄*/
  __HAL_LINKDMA(&Spi1Handle, hdmatx, HdmaCh1);

  HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);

//  Spi1Handle.Init.DataSize = SPI_DATASIZE_16BIT;
//  HAL_SPI_DeInit(&Spi1Handle);
//  /*SPI初始化*/
//  HAL_SPI_Init(&Spi1Handle);
}
